#include "stdafx.h"
#include "XTabImpl.h"

#include <XBSTR.h>
#include <Util.h>
#include <UIUtil.h>
#include <XStrUtil.h>
#include <IXImage.h>
#include <IXLabel.h>


static const LPCTSTR g_tabGroupName = _T("TabButton");
static const LPCTSTR g_tabButtonIdFormat = _T("Tab_%1");
static const LPCTSTR g_tabButtonTitleId = _T("tbti");
static const LPCTSTR g_tabButtonImageId = _T("tbii");
//////////////////////////////////////////////////////////////////////////

template <class I>
CXTabImpl<I>::CXTabImpl()
{
    m_bHorz = FALSE;
    m_nButtonMargin = 10;
    m_ButtonSize.cx = 48;
    m_ButtonSize.cy = 48;
    m_pBtnLayout = NULL;
    m_nCurSel = -1;

    m_ImageSize.cx = 32;
    m_ImageSize.cy = 32;

    memset(&m_rcInternalMargin, 0, sizeof(m_rcInternalMargin));

    m_pTitleFont = NULL;
    m_pTitleTextEnv = NULL;
#if _IS_UI_FOCUS_ENABLED_
    ModifyControlFlags(ESkin_NeedKeyMsg, TRUE);
#endif // _IS_UI_FOCUS_ENABLED_
}

template <class I>
CXTabImpl<I>::~CXTabImpl()
{
}

//////////////////////////////////////////////////////////////////////////
// IXTab
template <class I>
void CXTabImpl<I>::SetButtonMargin(int nMargin)
{
    if(m_nButtonMargin != nMargin)
    {
        m_nButtonMargin = nMargin;
        if(m_pBtnLayout != NULL)
        {
            TabInfoVector::iterator IteTab = m_vctTabInfo.begin();
            for(; IteTab != m_vctTabInfo.end(); ++ IteTab)
            {
                stTabInfo& info = *IteTab;
                int nLeft, nTop, nRight, nBottom;
                info.pButton->get_Margin(&nLeft, &nTop, &nRight, &nBottom);
                info.pButton->put_Margin(nMargin, nTop, nRight, nBottom);
            }
        }
    }
}

template <class I>
void CXTabImpl<I>::SetButtonSize(int nWidth, int nHeight)
{
    if(m_ButtonSize.cx != nWidth || m_ButtonSize.cy != nHeight)
    {
        m_ButtonSize.cx = nWidth;
        m_ButtonSize.cy = nHeight;

        if(m_pBtnLayout != NULL)
            m_pBtnLayout->put_Size(m_bHorz ? m_ButtonSize.cx : m_pBtnLayout->GetWidth(), m_bHorz ? m_pBtnLayout->GetHeight() : m_ButtonSize.cy);

        AdjustFramePos();
    }
}

template <class I>
void CXTabImpl<I>::SetTitleTextFont(IN IXFont* pFont)
{
    XSAFE_RELEASE(m_pTitleFont);

    m_pTitleFont = pFont;
    if(pFont == NULL)
        return;

    IXControl* pTitle = NULL;
    TabInfoVector::iterator IteTab = m_vctTabInfo.begin();
    for(; IteTab != m_vctTabInfo.end(); ++ IteTab)
    {
        stTabInfo& info = *IteTab;
        if(SUCCEEDED(info.pButton->GetItemById(g_tabButtonTitleId, &pTitle)) && pTitle != NULL)
        {
            pTitle->put_Font(m_pTitleFont);
        }
    }
}

template <class I>
void CXTabImpl<I>::SetTitleTextEnv(IN IXTextEnv* pTextEnv)
{
    XSAFE_RELEASE(m_pTitleTextEnv);

    m_pTitleTextEnv = pTextEnv;
    if(pTextEnv == NULL)
        return;

    IXControl* pTitle = NULL;
    TabInfoVector::iterator IteTab = m_vctTabInfo.begin();
    for(; IteTab != m_vctTabInfo.end(); ++ IteTab)
    {
        stTabInfo& info = *IteTab;
        if(SUCCEEDED(info.pButton->GetItemById(g_tabButtonTitleId, &pTitle)) && pTitle != NULL)
        {
            pTitle->put_TextEnv(m_pTitleTextEnv);
        }
    }
}

template <class I>
void CXTabImpl<I>::SetInternalMargin(IN int nLeft, IN int nTop, IN int nRight, IN int nBottom)
{
    if(nLeft != m_rcInternalMargin.left
        || nTop != m_rcInternalMargin.top
        || nRight != m_rcInternalMargin.right
        || nBottom != m_rcInternalMargin.bottom)
    {
        m_rcInternalMargin.left = nLeft;
        m_rcInternalMargin.top = nTop;
        m_rcInternalMargin.right = nRight;
        m_rcInternalMargin.bottom = nBottom;
        XASSERT_WARNING(m_vctTabInfo.size() <= 0, _T("InternalMargin must be used before any item inserted"));
    }
}

template <class I>
void CXTabImpl<I>::SetImageSize(IN int nImageWidth, IN int nImageHeight)
{
    m_ImageSize.cx = nImageWidth;
    m_ImageSize.cy = nImageHeight;
    //TODO: 
}

template <class I>
void CXTabImpl<I>::SetDirection(BOOL bHorz)
{
    if((!!bHorz) != (!!m_bHorz))
    {
        m_bHorz = bHorz;
        if(m_pBtnLayout != NULL)
        {
            m_pBtnLayout->SetLayoutType(m_bHorz ? Layout_Vert : Layout_Horz);
            m_pBtnLayout->SetFrameLayoutType(m_bHorz ? FLT_VFill : FLT_HFill);

            AdjustFramePos();
        }
    }
}

template <class I>
HRESULT CXTabImpl<I>::InsertItem(int nIndex, LPCTSTR szTabName, IXTabContent* pContent)
{
    stTabInfo info;
    info.pContent = pContent;

    TCHAR szImagePath[MAX_PATH];
    INT nHCount = 0, nVCount = 1;
    pContent->OnGetBkImagePath(szTabName, szImagePath, &nHCount, &nVCount);

    XString strId = XString(g_tabButtonIdFormat).arg(szTabName);
    strId = XStrUtil::ToLower(strId);

    info.strName = szTabName;

    RECT rcButton = {0, 0, m_ButtonSize.cx, m_ButtonSize.cy};

    IXRadioBox* pButton = NULL;
    HRESULT hResult = Util::CreateObject(&pButton);
    pButton->Create(m_pBtnLayout, &rcButton, strId);
    pButton->put_GroupName(g_tabGroupName);
    pButton->put_ImagePath(szImagePath, nHCount, nVCount, NULL);
    pButton->put_ScaleImage(TRUE);
    pButton->put_Margin(m_nButtonMargin, 0, 0, 0);
    RegisterEvent(pButton, FrameEvent_Clicked, &CXTabImpl<I>::OnTabButtonClicked);

    info.pButton = pButton;
    info.pFrame = NULL;
    info.pContent = pContent;

    InitTabButton(info.strName.GetData(), info.pButton, info.pContent);

    nIndex = (nIndex > (int)m_vctTabInfo.size()) ? (int)m_vctTabInfo.size() : nIndex;
    m_vctTabInfo.insert(m_vctTabInfo.begin() + nIndex, info);
    return S_OK;
}

template <class I>
HRESULT CXTabImpl<I>::DeleteItem(LPCTSTR szTabName)
{
    size_t uIndex = FindItemByName(szTabName);
    if(uIndex == -1)
        return E_INVALIDARG;

    stTabInfo& info = m_vctTabInfo[uIndex];
    m_pBtnLayout->DelChild(info.pButton);
    if(info.pFrame != NULL)
        m_pBtnLayout->DelChild(info.pFrame);

    m_vctTabInfo.erase(m_vctTabInfo.begin() + uIndex);
    return S_OK;
}

template <class I>
int CXTabImpl<I>::GetCurSel()
{
    return m_nCurSel;
}

template <class I>
UINT CXTabImpl<I>::GetCount()
{
    return m_vctTabInfo.size();
}

template <class I>
HRESULT CXTabImpl<I>::ShowTab(IN LPCTSTR szTabName)
{
    UINT uIndex = FindItemByName(szTabName);
    if(uIndex == -1)
        return E_INVALIDARG;

    return ShowTabByIndex((int)uIndex);
}

template <class I>
void CXTabImpl<I>::GetFrameRect(OUT RECT* prcFrame)
{
    get_WindowRect(prcFrame);

    if(m_bHorz)
        prcFrame->left += m_ButtonSize.cx;
    else
        prcFrame->top += m_ButtonSize.cy;
}

template <class I>
IXTabContent* CXTabImpl<I>::GetContentByIndex(IN LPCTSTR szTabName)
{
    IXTabContent* pTabContent = NULL;
    TabInfoVector::iterator IteTab = m_vctTabInfo.begin();
    for(; IteTab != m_vctTabInfo.end(); ++ IteTab)
    {
        stTabInfo& info = *IteTab;
        if(info.strName == szTabName)
        {
            pTabContent = info.pContent;
        }
    }
    return pTabContent;
}

//////////////////////////////////////////////////////////////////////////
// CXControlImpl
template <class I>
void CXTabImpl<I>::OnCreate()
{
    superclass::OnCreate();

    if(SUCCEEDED(Util::CreateObject(&m_pBtnLayout)))
    {
        RECT rcStub = {0, 0, m_ButtonSize.cx, m_ButtonSize.cy};
        m_pBtnLayout->Create(this, &rcStub, NULL);
        m_pBtnLayout->SetLayoutType(m_bHorz ? Layout_Vert : Layout_Horz);
        m_pBtnLayout->EnableScrollBar(FALSE);
        m_pBtnLayout->SetFrameLayoutType(m_bHorz ? FLT_VFill : FLT_HFill);
    }
}

//////////////////////////////////////////////////////////////////////////
// XTabImpl
template <class I>
size_t CXTabImpl<I>::FindItemByName(LPCTSTR szName)
{
    XString strId = XString(g_tabButtonIdFormat).arg(szName);
    strId = XStrUtil::ToLower(strId);

    return FindItemByItemId(strId.GetData());
}

template <class I>
size_t CXTabImpl<I>::FindItemByItemId(LPCTSTR szId)
{
    XString strId;

    TabInfoVector::iterator IteTab = m_vctTabInfo.begin();
    for(; IteTab != m_vctTabInfo.end(); ++ IteTab)
    {
        stTabInfo& info = *IteTab;

        strId = XString(g_tabButtonIdFormat).arg(info.strName);
        strId = XStrUtil::ToLower(strId);

        if(strId == szId)
        {
            break;
        }
    }
    if(IteTab == m_vctTabInfo.end())
        return E_INVALIDARG;
    return IteTab - m_vctTabInfo.begin();
}

template <class I>
HRESULT CXTabImpl<I>::ShowTabByIndex(int nIndex)
{
    if(m_nCurSel != -1)
    {
        stTabInfo& curTabInfo = m_vctTabInfo[m_nCurSel];
        if(curTabInfo.pFrame != NULL)
        {
            curTabInfo.pContent->OnShow(curTabInfo.strName.GetData(), FALSE);
            curTabInfo.pFrame->SetVisible(FALSE);
        }
    }

    stTabInfo& curTabInfo = m_vctTabInfo[nIndex];
    curTabInfo.pButton->put_Check(TRUE);
    if(curTabInfo.pFrame == NULL)
    {
        if(SUCCEEDED(Util::CreateObject(&curTabInfo.pFrame)))
        {
            POINT PtStub = {0};
            curTabInfo.pFrame->Create(this, &PtStub, NULL);
            curTabInfo.pFrame->put_Margin(m_bHorz ? m_ButtonSize.cx : 0, (!m_bHorz) ? m_ButtonSize.cy : 0, 0, 0);
            curTabInfo.pFrame->SetFrameLayoutType(FLT_HFill | FLT_VFill);
            curTabInfo.pContent->OnCreateFrame(curTabInfo.strName.GetData(), curTabInfo.pFrame);
        }
    }

    curTabInfo.pFrame->SetVisible(TRUE);
    curTabInfo.pContent->OnShow(curTabInfo.strName.GetData(), TRUE);
    m_nCurSel = nIndex;
    return S_OK;
}

template <class I>
void CXTabImpl<I>::OnTabButtonClicked(IXControl* pSrcControl, LPARAM lParam)
{
    XBSTR bstrId;
    pSrcControl->get_ItemId(&bstrId);

    size_t nIndex = FindItemByItemId(bstrId);
    if(nIndex == -1 || m_nCurSel == nIndex)
        return;

    ShowTabByIndex(nIndex);
}

template <class I>
void CXTabImpl<I>::AdjustFramePos()
{
    TabInfoVector::iterator IteTab = m_vctTabInfo.begin();
    for(; IteTab != m_vctTabInfo.end(); ++ IteTab)
    {
        stTabInfo& info = *IteTab;
        info.pFrame->put_Margin(m_bHorz ? m_ButtonSize.cx : 0, (!m_bHorz) ? m_ButtonSize.cy : 0, 0, 0);
    }
}

template <class I>
void CXTabImpl<I>::InitTabButton(LPCTSTR szTabName, IXRadioBox* pButton, IXTabContent* pContent)
{
    TCHAR szTitle[TAB_TITLE_MAX_LEN] = {0};
    TCHAR szImagePath[TAB_IMAGE_PATH_MAX_LEN] = {0};
    TabButtonStyle style = TBS_BottomText;

    // Acquire information
    pContent->OnGetButtonInfo(szTabName, szTitle, szImagePath, &style);
    szTitle[TAB_TITLE_MAX_LEN - 1] = 0;
    szImagePath[TAB_IMAGE_PATH_MAX_LEN - 1] = 0;

    if(style == TBS_Custom)
        return;

    // Image
    if(style != TBS_TextOnly)
    {
        IXImage* pImage = NULL;
        RECT rcImage = {0, 0, m_ImageSize.cx, m_ImageSize.cy};
        Util::CreateObject(&pImage);
        pImage->Create(pButton, &rcImage, g_tabButtonImageId);
        pImage->put_Image(szImagePath);

        RECT rcMargin = m_rcInternalMargin;
        DWORD dwLayout = 0;
        if(style == TBS_LeftText)
        {
            dwLayout = FLT_VCenter | FLT_Right;
            rcMargin.left = 0;
        }
        else if(style == TBS_TopText)
        {
            dwLayout = FLT_HCenter | FLT_Bottom;
            rcMargin.top = 0;
        }
        else if(style == TBS_RightText)
        {
            dwLayout = FLT_VCenter | FLT_Left;
            rcMargin.right = 0;
        }
        else if(style == TBS_BottomText)
        {
            dwLayout = FLT_HCenter | FLT_Top;
            rcMargin.bottom = 0;
        }
        else if(style == TBS_ImageOnly)
        {
            dwLayout = FLT_HCenter | FLT_VCenter;
        }
        pImage->SetFrameLayoutType(dwLayout);
        pImage->put_Margin(rcMargin.left, rcMargin.top, rcMargin.right, rcMargin.bottom);
    }

    // Text
    if(style != TBS_ImageOnly)
    {
        IXLabel* pText = NULL;
        POINT ptText = {0, 0};
        Util::CreateObject(&pText);
        pText->Create(pButton, &ptText, g_tabButtonTitleId);
        pText->put_Text(szTitle);
        pText->put_MaxSize(pButton->GetWidth(), -1);

        if(m_pTitleFont != NULL)
            pText->put_Font(m_pTitleFont);
        if(m_pTitleTextEnv != NULL)
            pText->put_TextEnv(m_pTitleTextEnv);

        RECT rcMargin = m_rcInternalMargin;
        DWORD dwLayout = 0;
        if(style == TBS_LeftText)
        {
            dwLayout = FLT_VCenter | FLT_Left;
            rcMargin.right = 0;
        }
        else if(style == TBS_TopText)
        {
            dwLayout = FLT_HCenter | FLT_Top;
            rcMargin.bottom = 0;
        }
        else if(style == TBS_RightText)
        {
            dwLayout = FLT_VCenter | FLT_Right;
            rcMargin.left = 0;
        }
        else if(style == TBS_BottomText)
        {
            dwLayout = FLT_HCenter | FLT_Bottom;
            rcMargin.top = 0;
        }
        else if(style == TBS_TextOnly)
        {
            dwLayout = FLT_HCenter | FLT_VCenter;
        }
        pText->SetFrameLayoutType(dwLayout);
        pText->put_Margin(rcMargin.left, rcMargin.top, rcMargin.right, rcMargin.bottom);
    }
}
